#pragma once

#include <iostream>
#include <string>
#include <strings.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>

namespace Client
{
	using namespace std;

	// 作为一个客户端,主要的编写逻辑同服务器差不多
	class UDPClient
	{
	public:
		enum
		{
			USAGE_ERR = 1,
			SOCKET_ERR,
			BIND_ERR
		};

		// 虽然客户端的端口和IP并不重要,但是必须要有!
		UDPClient(const string &IP, const uint16_t &port)
			: _IP(IP), _port(port)
		{
		}

		void init()
		{
			// 首先创建Socket
			_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
			if (_socket_fd == -1)
			{
				std::cerr << "bulid socket failed!" << strerror(errno) << endl;
				exit(SOCKET_ERR);
			}
			std::cout << "socket success: "
					  << " : " << _socket_fd << endl;
		}

		// 为了更好的支持网络聊天服务，我们需要将客户端改造成双线程的模式运行，一个线程专门获取信息，另一个只发送信息

		static void *readmessage(void *args)
		{
			int sock_fd = *(static_cast<int *>(args));

			// 先分离，不要让父进程等待。
			pthread_detach(pthread_self());
			// 读者线程持续获取网络内的信息
			while (true)
			{
				char buffer[1024];
				struct sockaddr_in tmp;
				socklen_t len = sizeof(tmp);
				// 不能只发不收
				size_t ret = recvfrom(sock_fd, buffer, sizeof(buffer) - 1, 0, (sockaddr *)&tmp, &len);
				if (ret >= 0)
					buffer[ret] = 0;

				std::cout << buffer << endl;
			}
			return nullptr;
		}

		void start()
		{
			pthread_create(&_reader, nullptr, readmessage, (void *)&_socket_fd);

			struct sockaddr_in local;
			bzero(&local, sizeof(local));
			// 填写SockerAddr字段

			local.sin_family = AF_INET;
			// 地址需要转换
			local.sin_addr.s_addr = inet_addr(_IP.c_str());
			local.sin_port = htons(_port);

			// 作为一个客户端,我们不需要程序员显示的bind,系统会自动的帮我们绑定
			string message;
			char cmdline[1024];
			while (true)
			{
				// std::cout<<"请输入:";
				fprintf(stderr, "XXX@VM-12-5-centos PK的服务器]$");
                fflush(stderr);

				// std::cout << "XXX@VM-12-5-centos PK的服务器]$ ";
				// cin >> message;

				// 
				fgets(cmdline, sizeof(cmdline), stdin);
				// 输入的最后还有一个\n，这个老坑了。
				cmdline[strlen(cmdline)-1] = 0;
				message = cmdline;

				sendto(_socket_fd, message.c_str(), message.size(), 0, (sockaddr *)&local, sizeof(local));

				// cout<<"服务器翻译结果为："<<responce<<endl;
			}
		}

		~UDPClient()
		{
		}

	private:
		// 还是先创建变量和对应的Socket
		int _socket_fd = -1;
		uint16_t _port;
		string _IP;

		pthread_t _reader;
	};

}
